//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.Provenance.Controls.Presenter
{
    using System.Collections.ObjectModel;
    using System.Windows;
    using Microsoft.Research.Provenance.Controls.View;
    using Microsoft.Research.Provenance.ProvenanceDataService;
    using Microsoft.Research.ProvenanceCommon.Model;
    using Microsoft.Research.ProvenanceInterfaces;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using System.ComponentModel;
    using Microsoft.Practices.Unity;
    using System;
    using Microsoft.Research.ScientificWorkflow.TridentModel;
    using System.Text;

    public class ActivityInputOutputPresenter : IProvenancePresenter, INotifyPropertyChanged ,IDisposable
    {
        /// <summary>
        /// The helper class which fetches data from the registry.
        /// </summary>
       // private DataRetriever dataRetriever;

        /// <summary>
        /// Holds the UnityContainer
        /// </summary>
        private IUnityContainer container;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="view">The view which displays the properties.</param>
        public ActivityInputOutputPresenter(IUnityContainer container, ActivityInputOutputView view)
        {
            this.View = view;
            this.container = container;

            this.InputPropertyCollection = new ObservableCollection<ActivityProperty>();
            this.OutputPropertyCollection = new ObservableCollection<ActivityProperty>();

            view.Model = this;
        }

        /// <summary>
        /// The collection of input properties.
        /// </summary>
        public ObservableCollection<ActivityProperty> InputPropertyCollection { get; private set; }

        /// <summary>
        /// The collection of output properties.
        /// </summary>
        public ObservableCollection<ActivityProperty> OutputPropertyCollection { get; private set; }

        /// <summary>
        /// The view which displays the properties.
        /// </summary>
        public UIElement View { get; set; }

        /// <summary>
        /// Activity label.
        /// </summary>
        private string activityLabel;

        /// <summary>
        /// Activity label.
        /// </summary>
        public string ActivityLabel
        {
            get
            {
                return this.activityLabel;
            }
            private set
            {
                this.activityLabel = value;
                this.OnNotifyPropertyChanged("ActivityLabel");
            }
        }
        
        /// <summary>
        /// Inidicates whether data is not present.
        /// </summary>
        private bool doesNotContainInputParameters;

        /// <summary>
        /// Gets whether data is not present.
        /// </summary>
        public bool DoesNotContainInputParameters
        {
            get
            {
                return this.doesNotContainInputParameters;
            }
            private set
            {
                this.doesNotContainInputParameters = value;
                this.OnNotifyPropertyChanged("DoesNotContainInputParameters");
            }
        }

        /// <summary>
        /// Inidicates whether data is present.
        /// </summary>
        private bool containInputParameters;

        /// <summary>
        /// Gets whether data is present.
        /// </summary>
        public bool ContainInputParameters
        {
            get
            {
                return this.containInputParameters;
            }
            private set
            {
                this.containInputParameters = value;
                this.DoesNotContainInputParameters = !this.ContainInputParameters;
                this.OnNotifyPropertyChanged("ContainInputParameters");
            }
        }

        /// <summary>
        /// Inidicates whether data is not present.
        /// </summary>
        private bool doesNotContainOutputParameters;

        /// <summary>
        /// Gets whether data is not present.
        /// </summary>
        public bool DoesNotContainOutputParameters
        {
            get
            {
                return this.doesNotContainOutputParameters;
            }
            private set
            {
                this.doesNotContainOutputParameters = value;
                this.OnNotifyPropertyChanged("DoesNotContainOutputParameters");
            }
        }

        /// <summary>
        /// Inidicates whether data is present.
        /// </summary>
        private bool containOutputParameters;

        /// <summary>
        /// Gets whether data is present.
        /// </summary>
        public bool ContainOutputParameters
        {
            get
            {
                return this.containOutputParameters;
            }
            private set
            {
                this.containOutputParameters = value;
                this.DoesNotContainOutputParameters = !this.ContainOutputParameters;
                this.OnNotifyPropertyChanged("ContainOutputParameters");
            }
        }

        /// <summary>
        /// BreadCrumb text binded with UI.
        /// </summary>
        private StringBuilder breadcrumb;

        /// <summary>
        /// Gets or sets the Breadcrumb property, binded with UI.
        /// </summary>
        public string Breadcrumb
        {
            get
            {
                return this.breadcrumb.ToString();
            }
            set
            {
                this.breadcrumb = new StringBuilder();
                this.breadcrumb.Append(value);

                // Don't display breadcrumb if not applicable.
                if (string.IsNullOrEmpty(this.Breadcrumb))
                    IsBreadcrumbNull = false;
                else
                    IsBreadcrumbNull = true;

                this.OnNotifyPropertyChanged("Breadcrumb");
            }
        }

        /// <summary>
        /// Inidicates whether breadcrumb text is not present.
        /// </summary>
        private bool isBreadcrumbNull;

        /// <summary>
        /// Gets or sets a value indicating whether breadcrumb is null.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if breadcrumb is null; otherwise, <c>false</c>.
        /// </value>
        public bool IsBreadcrumbNull
        {
            get
            {
                return this.isBreadcrumbNull;
            }
            private set
            {
                this.isBreadcrumbNull = value;
                this.OnNotifyPropertyChanged("IsBreadcrumbNull");
            }
        }

        #region IProvenancePresenter Members

        /// <summary>
        /// Display the view of the presenter and retrieve the parameters.
        /// </summary>
        /// <param name="compositeModel">The activity for which the parameters are to be retrieved.</param>
        public void Show(BaseModel model)
        {
            string breadcrumb = string.Empty;

            try
            {
                Collection<ActivityProperty> parameterModels = this.container.Resolve<DataRetriever>().GetParameters(model, ref breadcrumb);

                this.ActivityLabel = model.Name;

                if (parameterModels != null)
                {
                    foreach (ActivityProperty parameter in parameterModels)
                    {
                        if (parameter.Direction == Microsoft.Research.DataLayer.DirectionType.Input)
                        {
                            this.InputPropertyCollection.Add(parameter);
                        }
                        else
                        {
                            this.OutputPropertyCollection.Add(parameter);
                        }
                    }
                }

                this.Breadcrumb = breadcrumb;

                this.ContainInputParameters = this.InputPropertyCollection.Count > 0;
                this.ContainOutputParameters = this.OutputPropertyCollection.Count > 0;

                this.View.Visibility = Visibility.Visible;
            }
            catch (TridentCustomException ex)
            {
                TridentMessageBox.ShowTridentErrorMessageBox(ex.Message);
            }
        }

        /// <summary>
        /// Hide the view.
        /// </summary>
        public void Hide()
        {
            this.InputPropertyCollection.Clear();
            this.OutputPropertyCollection.Clear();
            this.View.Visibility = Visibility.Collapsed;
        }

        #endregion

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Event for property change.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raise property changed eventargs.
        /// </summary>
        /// <param name="changeProperty">Property anme.</param>
        private void OnNotifyPropertyChanged(string changeProperty)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(changeProperty));
            }
        }

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Clears the collection and View Object
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// nullify and Disposes the object 
        /// </summary>
        /// <param name="disposing"></param>
        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                this.container.Dispose(); 
                this.View = null;
            }
        }

        #endregion
    }
}
